--===========================================================================--
-- Naziv		: Registers
-- Ime fajla	: reg.vhdl  
-- Verzija		: 0.2
--===========================================================================-- 

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity reg is 
	  port (
		 --IN
		   reset,clk,clk2      : in  std_logic;
		  -- opcode_id   		   : in std_logic_vector(4 downto 0);
		   opcode_of   		   : in std_logic_vector(4 downto 0);
		   R1_of,R2_of,R3_of   : in std_logic_vector(3 downto 0);	
		   Reg_wb              : in std_logic_vector(3 downto 0); 
		   Data_wb             : in std_logic_vector(15 downto 0);
		   write_wb            : in std_logic;
		   
		 --OUT
		   Reg1,Reg2,Reg3   : out std_logic_vector(15 downto 0);
		   stall         	: buffer std_logic;
		   flush_ex 	    : out std_logic;
		   D_ABUS           : out std_logic_vector (15 downto 0);--Adresna magistrala za podatke
		   D_DBUS           : out std_logic_vector(15 downto 0);--Data magistrala za podatke
		   D_RD,D_WR  		: out std_logic --Kontrolna magistrala za podatke
	  );
end;

architecture reg_AR of reg is

type reg_array is array( 15 downto 0 ) of std_logic_vector(15  downto 0);
signal reg: reg_array;
type  flagarray is array (15 downto 0) of std_logic;
signal	opcode_reg   :  std_logic_vector(4 downto 0);
signal 	DReg1,DReg2  :  std_logic_vector(3 downto 0);	

begin
	reg_PR: process (reset, clk) is
	variable flag : flagarray;
	variable flagR1,flagR2,flagR3 : std_logic:='0';
	--variable stallcounter :std_logic:='0';
	variable wasStole:std_logic:='0';
	begin
		if reset='1' then

			--prebacio u heksa zapis
			Reg1<=X"0000";
			Reg2<=X"0000";
			Reg3<=X"0000";
			
			flag(0):='0';reg(0)<=X"0000";
			flag(1):='0';reg(1)<=X"0001";
			flag(2):='0';reg(2)<=X"0002";
			flag(3):='0';reg(3)<=X"0003";
			flag(4):='0';reg(4)<=X"0004";
			flag(5):='0';reg(5)<=X"0005";
			flag(6):='0';reg(6)<=X"0006";
			flag(7):='0';reg(7)<=X"0007";
			flag(8):='0';reg(8)<=X"0008";
			flag(9):='0';reg(9)<=X"0009";
			flag(10):='0';reg(10)<=X"000A";
			flag(11):='0';reg(11)<=X"000B";
			flag(12):='0';reg(12)<=X"000C";
			flag(13):='0';reg(13)<=X"000D";
			flag(14):='0';reg(14)<=X"000E";
			flag(15):='0';reg(15)<=X"000F";
			
			stall <= '0';
			
		elsif( falling_edge(clk) ) then	
			--Ovde se upisuje u registar iz WB 
			if write_wb='1' then	
				reg(to_integer(unsigned(Reg_wb)))<=Data_wb;
				flag(to_integer(unsigned(Reg_wb))):='0';
				--TODO ??? Zasto ovde ne bi proveravali "stall", u toj slucaju nam ne treba "stallcounter"???
				--!!! ODGOVOR: I meni se "stallcounter" cini kao ne potreban, ali ajde za pocetak da ga ostavimo,
				-- 				pa ako sve bude radilo-onda cemo da ga izbacimo
				--if stallcounter = '1' then
					--stallcounter := '0';
				if stall = '1' then
						stall<='0';
						flush_ex<='0';
						wasStole:='1';
				end if;            				
			end if ;
			
			--Ovde se uzimaju odgovarajuci flegovi za registre R1,R2,R3 koji ucestvuju u instrukciji
			flagR1:=flag(to_integer(unsigned(R1_of)));
			flagR2:=flag(to_integer(unsigned(R2_of)));
			flagR3:=flag(to_integer(unsigned(R3_of)));
		   
		   --Ovde se proverava da li dolazi do stall, a ako ne citaju se trazeni registri
		   if (stall='0' or wasStole='1') then 		
				-- za instrukcije koje citaju 3 registra (skokovi): BG,BGE,BL,BLE,BE,BNE
--			    if opcode_id>="01001" and opcode_id <= "01110" then   	 a mozda bi cak trebalo da bude i opcode_reg
			    if opcode_of>="01001" and opcode_of <= "01110" then   	
					if flagR1='1' or flagR2='1' or flagR3='1' then  
						stall<='1';
						--TODO ??? Zasto ovde nema, kao i kod ostalih instrukcija???
						--!!! ODGOVOR: Zato sto ove instrukcije nista ne upisuju, pa zato nema potrebe da se radi flush
						--!!! ISPRAVKA: Treba i ovde flush, koji sam konj izgubio sam pola sata zivota zbog ovoga!
						flush_ex<='1';
						--stallcounter:='1';		
					else
						Reg1<=reg(to_integer(unsigned(R1_of)));
						Reg2<=reg(to_integer(unsigned(R2_of)));
						Reg3<=reg(to_integer(unsigned(R3_of)));
					end if;				-- ne treba da se setuje flag jer se radi samo citanje
				
				-- za instrukcije koje citaju 2 registra: ADD,SUB,AND,OR,XOR
--				elsif opcode_id>="00011" and opcode_id <= "00111" then  
				elsif opcode_of>="00011" and opcode_of <= "00111" then  
					if flagR1='1' or flagR2='1' then  
						stall<='1';
						flush_ex<='1';
						--stallcounter:='1';
					else
						Reg1<=reg(to_integer(unsigned(R1_of)));
						Reg2<=reg(to_integer(unsigned(R2_of)));
						flag(to_integer(unsigned(R3_of))):='1';    --setuje flag za ovaj registar ako neko pokusa da cita bice stall		
					end if;				
        					
        		--za ove instrukcije se cita samo R1 a upisuje u R3: MOV,ROR		
--				elsif opcode_id>="00001" and opcode_id <= "00010" then 
				elsif opcode_of>="00001" and opcode_of <= "00010" then 
					if flagR1='1'  then 
						stall<='1';
						flush_ex<='1';
						--stallcounter:='1';
					else 
						Reg1<=reg(to_integer(unsigned(R1_of)));
						flag(to_integer(unsigned(R3_of))):='1'; --setuje flag za ovaj registar ako neko pokusa da cita bice stall		
					end if;
					
				--za ove instrukcije se cita samo R1 a upisuje u R2: LOAD,NOT		
--				elsif opcode_id>="00001" and opcode_id <= "00010" then 
				elsif opcode_of="10001" or opcode_of = "10111" then 
					if flagR1='1'  then 
						stall<='1';
						flush_ex<='1';
						--stallcounter:='1';
					else 
						Reg1<=reg(to_integer(unsigned(R1_of)));
						flag(to_integer(unsigned(R2_of))):='1'; --setuje flag za ovaj registar ako neko pokusa da cita bice stall		
					end if;
				
				--za ove instrukcije se cita samo R1: PUSH,JSR
--				elsif opcode_id="10011" or opcode_id="10101" then 
				elsif opcode_of="10011" or opcode_of="10101" then 
					if flagR1='1'  then 
						stall<='1';
						flush_ex<='1';
						--stallcounter:='1';
					else 
						Reg1<=reg(to_integer(unsigned(R1_of))); -- ne treba da se setuje flag jer se radi samo citanje
					end if;
				
				--za ove instrukcije se samo upisuje u R1: POPREL,POP
--				elsif opcode_id="01000" or opcode_id="10100" then 
				elsif opcode_of="01000" or opcode_of="10100" then 
					
						flag(to_integer(unsigned(R1_of))):='1'; --setuje flag za ovaj registar ako neko pokusa da cita bice stall		
				
				--za ove instrukcije se cita iz R1 i R2: STORE
--				elsif opcode_id="10010" then 
				elsif opcode_of="10010" then 
					if flagR1='1' or flagR2='1'  then 
						stall<='1';
						flush_ex<='1';
						--stallcounter:='1';
					end if;	
			    end if;	
			
			--Ovde se prosledjuje registar u koji se upisuje
			if (Reg_wb=R1_of and (wasStole='1'or write_wb='1')) then Reg1<=Data_wb;
			end if;
			if (Reg_wb=R2_of and (wasStole='1'or write_wb='1')) then Reg2<=Data_wb;
			end if;
			if (Reg_wb=R3_of and (wasStole='1'or write_wb='1')) then Reg3<=Data_wb;
			end if;
			--Ovde se resetuje wasStole
			wasStole:='0';
			
			end if;
			
		end if;
	end process; 
	
	reg_DMem_PR: process(clk,reset) is
	--???Cemu ovde sluzi count??? 
	--Meni se cini da moze i bez njega, verovatno ima neke veze sa kasnjenjem clk2 od Pi/2
	--TODO Ajde Srecko pogledaj ovo, pa ako se slazes i ti da ne treba da izbacimo glupi count
	--count je obicna glupost i nije potrebno
	--variable count: integer:=0;	
	begin
	    if reset='1' then
			--count:=0;
			opcode_reg<="00000";
			DReg1<="0000";
			DReg1<="0000";	
		elsif rising_edge(clk) then 
			--count:=count+1;
			--if count=2 then 
				--count:=0;
				opcode_reg<=opcode_of;
				--opcode_reg<=opcode_id; previse rano dolazi signal
				DReg1<=R1_of;
				DReg2<=R2_of;
			--end if;	
		end if;
	end process;
	
	  D_ABUS<=reg(to_integer(unsigned(DReg1)))  when (opcode_reg="10001" and stall='0') else --LOAD
              reg(to_integer(unsigned(DReg2)))  when (opcode_reg="10010" and stall='0') else --STORE  
			  "ZZZZZZZZZZZZZZZZ";
	  D_RD<= '1' when (opcode_reg="10001" and stall='0')else  --LOAD
			  '0';
	  D_WR<= '1' when (opcode_reg="10010" and stall='0') else  --STORE
			  '0';
	  D_DBUS<=reg(to_integer(unsigned(DReg1)))  when (opcode_reg="10010" and stall='0') else --STORE             
           "ZZZZZZZZZZZZZZZZ";

end reg_AR;